package com.example.act6.study.service.impl;


import com.example.act6.common.entities.CommonResult;
import com.example.act6.common.entities.LayuiPage;
import com.example.act6.common.exception.BusinessException;
import com.example.act6.study.service.ActivitiDefineService;
import com.example.act6.utils.BeanUtils;
import com.example.act6.utils.Constant;
import com.example.act6.vo.ActReProcdefVo;
import com.example.act6.vo.ProcessDefinitionInfoVo;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
//import com.github.pagehelper.PageHelper;
//import com.github.pagehelper.PageInfo;
import org.activiti.bpmn.converter.BpmnXMLConverter;
import org.activiti.bpmn.model.BpmnModel;
import org.activiti.editor.constants.ModelDataJsonConstants;
import org.activiti.editor.language.json.converter.BpmnJsonConverter;
import org.activiti.engine.IdentityService;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.RuntimeService;
import org.activiti.engine.repository.Deployment;
import org.activiti.engine.repository.Model;
import org.activiti.engine.repository.ProcessDefinition;
import org.activiti.engine.repository.ProcessDefinitionQuery;
import org.activiti.engine.runtime.ProcessInstance;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import javax.imageio.ImageIO;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamReader;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.util.*;
import java.util.stream.Collectors;
import java.util.zip.ZipInputStream;

/**
 * Service实现类
 */
@Service
public class ActivitiDefineServiceImpl implements ActivitiDefineService {

    @Autowired
    private RuntimeService runtimeService;
    @Autowired
    private RepositoryService repositoryService;
    @Autowired
    private IdentityService identityService;


    @Override
    public InputStream resourceRead(String id, String proInsId, String resType) {
        return null;
    }

    @Override
    public CommonResult startProcessInstanceById(String processDefinitionId, String assignee) {
        // 设置发起人 指定谁可以领取该任务
        identityService.setAuthenticatedUserId(assignee);
        // 根据流程实例Id查询
        ProcessInstance processInstance = runtimeService.startProcessInstanceById(processDefinitionId);
        Map map = new HashMap();
        map.put("processInstanceId", processInstance.getId());
        map.put("deploymentId", processInstance.getDeploymentId());
        return CommonResult.ok(map);
    }

    @Override
    public LayuiPage<ActReProcdefVo> queryPage(Map<String, Object> params) {


        int page = Integer.parseInt(params.getOrDefault("page", "1").toString());
        int pageSize = Integer.parseInt(params.getOrDefault("pageSize", "10").toString());

        ProcessDefinitionQuery processDefinitionQuery = repositoryService.createProcessDefinitionQuery().latestVersion().orderByProcessDefinitionKey().asc();
        // 按目录查找分类
        String category = params.get("category") == null ? "" : params.get("category").toString();
        if (StringUtils.isNotBlank(category)) {
            processDefinitionQuery.processDefinitionCategory(category);
        }
        // 按key查找分类
        String key = params.get("key") == null ? "" : params.get("key").toString();
        if (StringUtils.isNotBlank(key)) {
            processDefinitionQuery.processDefinitionKey(key);
        }
        List<ProcessDefinition> processDefinitionList = processDefinitionQuery.listPage((page - 1) * pageSize, pageSize);
//        List<ProcessDefinition> processDefinitionList = processDefinitionQuery.list();
        List<ActReProcdefVo> collect = processDefinitionList.stream().map(o -> {
            String deploymentId = o.getDeploymentId();
            Deployment deployment = repositoryService.createDeploymentQuery().deploymentId(deploymentId).singleResult();

            ActReProcdefVo actReProcdefVo = BeanUtils.copyProperties(o, ActReProcdefVo.class);
            actReProcdefVo.setId(o.getId());
            actReProcdefVo.setKey(o.getKey());
            actReProcdefVo.setDeployTime(deployment == null ? null : deployment.getDeploymentTime());
            return actReProcdefVo;
        }).collect(Collectors.toList());

        return new LayuiPage(collect, processDefinitionQuery.count());
    }

    @Override
    public void delete(String deploymentId) {

    }

    /**
     * @return {@link CommonResult}
     * @Author jrw
     * @Description 级联删除所以包括流程实例参数等；否则只是删除流程实例；注意流程实例被启动了是无法删除的
     * @Date 2022/3/9 9:09
     * @Param cascade:true 级联删除 false;不级联删除
     **/
    @Override
    public CommonResult deleteBatch(String deploymentIds, Boolean cascade) {
        repositoryService.deleteDeployment(deploymentIds, cascade);
        return CommonResult.ok();
    }

    @Override
    public CommonResult deploy(String exportDir, MultipartFile file) {
        String fileName = file.getOriginalFilename();
        Deployment deployment = null;
        List<ProcessDefinitionInfoVo> processDefinitionInfoVoList = new ArrayList<>();
        try {
            InputStream fileInputStream = file.getInputStream();
            String extension = FilenameUtils.getExtension(fileName);
            if (Constant.ZIP.equals(extension) || Constant.BAR.equals(extension)) {
                ZipInputStream zip = new ZipInputStream(fileInputStream);
                deployment = repositoryService.createDeployment().addZipInputStream(zip).deploy();
            } else if (Constant.PNG.equals(extension)) {
                deployment = repositoryService.createDeployment().addInputStream(fileName, fileInputStream).deploy();
            } else if (fileName.indexOf(Constant.BPMN20) != -1) {
                deployment = repositoryService.createDeployment().addInputStream(fileName, fileInputStream).deploy();
            } else if (Constant.BPMN.equals(extension)) {
                deployment = repositoryService.createDeployment().addInputStream(fileName, fileInputStream).deploy();
            } else {
                return CommonResult.error("不支持的文件类型");
            }

            List<ProcessDefinition> processDefinitionList = repositoryService.createProcessDefinitionQuery().deploymentId(deployment.getId()).list();

            // 设置流程分类
            processDefinitionList.forEach(o -> {
                repositoryService.setProcessDefinitionCategory(o.getId(), o.getCategory());
                ProcessDefinitionInfoVo vo = new ProcessDefinitionInfoVo();
                vo.setProcessDefinitionId(o.getId());
                vo.setMessage("部署成功，流程ID=" + o.getId());
                processDefinitionInfoVoList.add(vo);
            });

        } catch (IOException e) {
            e.printStackTrace();
            return CommonResult.error();
        }
        return CommonResult.ok(processDefinitionInfoVoList);
    }

    @Override
    public CommonResult convertToModel(String id) {
        ObjectNode modelNode = null;
        Model modelData = null;
        try {
            ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery().processDefinitionId(id).singleResult();
            InputStream bpmnStream = repositoryService.getResourceAsStream(processDefinition.getDeploymentId(), processDefinition.getResourceName());
            XMLInputFactory xif = XMLInputFactory.newInstance();
            InputStreamReader in = new InputStreamReader(bpmnStream, "UTF-8");
            XMLStreamReader xtr = xif.createXMLStreamReader(in);
            BpmnModel bpmnModel = new BpmnXMLConverter().convertToBpmnModel(xtr);

            BpmnJsonConverter converter = new BpmnJsonConverter();
            modelNode = converter.convertToJson(bpmnModel);
            modelData = repositoryService.newModel();
            modelData.setKey(processDefinition.getKey());
            modelData.setName(processDefinition.getResourceName());
            modelData.setCategory(processDefinition.getCategory());
            modelData.setDeploymentId(processDefinition.getDeploymentId());
            modelData.setVersion(Integer.parseInt(String.valueOf(repositoryService.createModelQuery().modelKey(modelData.getKey()).count() + 1)));

            ObjectNode modelObjectNode = new ObjectMapper().createObjectNode();
            modelObjectNode.put(ModelDataJsonConstants.MODEL_NAME, processDefinition.getName());
            modelObjectNode.put(ModelDataJsonConstants.MODEL_REVISION, modelData.getVersion());
            modelObjectNode.put(ModelDataJsonConstants.MODEL_DESCRIPTION, processDefinition.getDescription());
            modelData.setMetaInfo(modelObjectNode.toString());

            repositoryService.saveModel(modelData);
            repositoryService.addModelEditorSource(modelData.getId(), modelNode.toString().getBytes("utf-8"));
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        } catch (XMLStreamException e) {
            e.printStackTrace();
        } finally {
        }


        return CommonResult.ok(modelData);
    }

    @Override
    public CommonResult updateState(int state, String processDefinitionId) {
        String msg = "无操作";
        Date date = new Date();
        if (state == Constant.ONE) {
            try {
                repositoryService.activateProcessDefinitionById(processDefinitionId, true, null);
            } catch (Exception e) {
                throw new BusinessException("流程已经激活");
            }
            msg = "已激活ID为[" + processDefinitionId + "]的流程定义。";

        } else if (state == Constant.TWO) {
            try {
                repositoryService.suspendProcessDefinitionById(processDefinitionId, true, null);
            } catch (Exception e) {
                throw new RuntimeException("流程已经挂起");
            }
            msg = "已挂起ID为[" + processDefinitionId + "]的流程定义。";
        }
        return CommonResult.ok(msg);
    }

    @Override
    public void viewProcessImage(String processDefinitionId, HttpServletResponse response) {
        InputStream inputStream = repositoryService.getProcessDiagram(processDefinitionId);
        try {
            BufferedImage bufferedImage = ImageIO.read(inputStream);
            ServletOutputStream outputStream = response.getOutputStream();
            ImageIO.write(bufferedImage, Constant.PNG, outputStream);
            inputStream.close();
            outputStream.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }


}
